package com.sky.service.impl;

import com.sky.constant.MessageConstant;
import com.sky.exception.ReportException;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.UserMapper;
import com.sky.po.FoodStatisticsPO;
import com.sky.po.OrderStatisticsPO;
import com.sky.po.TurnoverStatisticsPO;
import com.sky.service.ReportService;
import com.sky.vo.OrderReportVO;
import com.sky.vo.SalesTop10ReportVO;
import com.sky.vo.TurnoverReportVO;
import com.sky.vo.UserReportVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.StringJoiner;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 在线报表业务接口实现类
 *
 * @Author Vsunks.v
 * @Date 2023/5/13 10:02
 * @Blog blog.sunxiaowei.net
 * @Description:
 */
@Service
public class ReportServiceImpl implements ReportService {

    @Autowired
    OrderMapper orderMapper;

    @Autowired
    UserMapper userMapper;

    /**
     * 商品销量排行统计在线报表
     *
     * @param begin 报表统计开始时间（以送达时间为准）
     * @param end   报表统计结束时间（以送达时间为准）
     * @return 报表数据
     */
    @Override
    public SalesTop10ReportVO salesTop10(LocalDate begin, LocalDate end) {
        // 0. 参数健壮性校验
        if (begin.isAfter(end)) {
            throw new ReportException(MessageConstant.ARGS_ERROR);
        }

        // 1. 查询统计结果，封装到PO对象的集合中
        List<FoodStatisticsPO> foodStatisticsPOs = orderMapper.listSaleQuantityByFood(
                LocalDateTime.of(begin, LocalTime.MIN), LocalDateTime.of(end, LocalTime.MAX));


        // 2. 封装PO数据到VO
        if (foodStatisticsPOs == null || foodStatisticsPOs.size() < 1) {
            return null;
        }

        StringJoiner foodNames = new StringJoiner(",");
        StringJoiner saleQuantities = new StringJoiner(",");

        // 2.1 拼接字符串
        foodStatisticsPOs.forEach(fsPO -> {
            foodNames.add(fsPO.getFoodName());
            saleQuantities.add(fsPO.getSaleQuantity() + "");
        });

        // 3. 返回数据
        return SalesTop10ReportVO.builder()
                .nameList(foodNames.toString())
                .numberList(saleQuantities.toString())
                .build();
    }

    /**
     * 营业额统计在线报表（日销售额）
     *
     * @param begin 报表统计开始时间（以送达时间为准）
     * @param end   报表统计结束时间（以送达时间为准）
     * @return 报表数据
     */
    @Override
    public TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {
        // 0. 参数健壮性校验
        if (begin.isAfter(end)) {
            throw new ReportException(MessageConstant.ARGS_ERROR);
        }

        // 1. 查询统计结果，封装到PO对象的集合中
        List<TurnoverStatisticsPO> turnoverStatisticsPOs = orderMapper.listTurnoverByDay(
                LocalDateTime.of(begin, LocalTime.MIN), LocalDateTime.of(end, LocalTime.MAX));


        // 2. 封装PO数据到VO
        if (turnoverStatisticsPOs == null || turnoverStatisticsPOs.size() < 1) {
            return null;
        }

        StringJoiner dates = new StringJoiner(",");
        StringJoiner turnovers = new StringJoiner(",");

        // 2.1 拼接字符串
        turnoverStatisticsPOs.forEach(tsPO -> {
            dates.add(tsPO.getUnit());
            turnovers.add(tsPO.getValue());
        });

        // 3. 返回数据
        return TurnoverReportVO.builder()
                .dateList(dates.toString())
                .turnoverList(turnovers.toString())
                .build();
    }

    /**
     * 订单量统计在线报表
     * <p>
     * 查询得到：日总订单量、日有效订单量
     * 计算得到：时间段内总订单量、时间段内总有效订单量、时间段内总订单完成率
     *
     * @param begin 报表统计开始时间（以下单时间为准）
     * @param end   报表统计结束时间（以下单时间为准）
     * @return 报表数据
     */
    @Override
    public OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {
        // 0. 参数健壮性校验
        if (begin.isAfter(end)) {
            throw new ReportException(MessageConstant.ARGS_ERROR);
        }

        // 1. 查询统计结果，封装到PO对象的集合中
        List<OrderStatisticsPO> orderStatisticsPOs = orderMapper.listOrderConutByDay(
                LocalDateTime.of(begin, LocalTime.MIN), LocalDateTime.of(end, LocalTime.MAX));


        // 2. 封装PO数据到VO
        if (orderStatisticsPOs == null || orderStatisticsPOs.size() < 1) {
            return null;
        }

        StringJoiner dates = new StringJoiner(",");     // 日期拼串
        StringJoiner orderCountsByDay = new StringJoiner(",");  // 日均总订单数拼串
        StringJoiner validOrderCountsByDay = new StringJoiner(","); // 日均完成订单数拼串

        AtomicInteger orderCounts = new AtomicInteger();        // 总订单数
        AtomicInteger validOrderCounts = new AtomicInteger();       // 总完成订单数

        // 2.1 拼接字符串
        orderStatisticsPOs.forEach(tsPO -> {
            dates.add(tsPO.getUnit());

            int orderCount = tsPO.getOrderCount();
            orderCountsByDay.add(orderCount + "");
            orderCounts.addAndGet(orderCount);

            int validOrderCount = tsPO.getValidOrderCount();
            validOrderCountsByDay.add(validOrderCount + "");
            validOrderCounts.addAndGet(validOrderCount);
        });

        // 计算时间段内总的订单完成率
        double rate = validOrderCounts.get() / (orderCounts.get() + 0.0);


        // 3. 返回数据
        return OrderReportVO.builder()
                .dateList(dates.toString())
                .orderCountList(orderCountsByDay.toString())
                .validOrderCountList(validOrderCountsByDay.toString())
                .totalOrderCount(orderCounts.get())
                .validOrderCount(validOrderCounts.get())
                .orderCompletionRate(rate)
                .build();
    }

    /**
     * 用户量统计在线报表（日总用户量、日新增用户量）
     *
     * @param begin 报表统计开始时间（以注册时间为准）
     * @param end   报表统计结束时间（以注册时间为准）
     * @return 报表数据
     */
    @Override
    public UserReportVO userStatistics(LocalDate begin, LocalDate end) {
        // 0. 参数健壮性校验
        if (begin.isAfter(end)) {
            throw new ReportException(MessageConstant.ARGS_ERROR);
        }

        // 1. 组织数据，生成[begin,end]所有日期对象，并存入一个集合
        ArrayList<LocalDate> dates = new ArrayList<>();
        while (!begin.isAfter(end)) {
            dates.add(begin);
            begin = begin.plusDays(1);
        }

        StringJoiner dateList = new StringJoiner(",");
        StringJoiner countAlls = new StringJoiner(",");
        StringJoiner countNews = new StringJoiner(",");
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        // 2. 遍历集合，获取每一个日期，调用 mapper查询
        dates.forEach(date -> {
            int countAll = userMapper.countAllByCreateDate(date);
            int countNew = userMapper.countNewByCreateDate(date);
            dateList.add(dtf.format(date));
            countAlls.add(countAll + "");
            countNews.add(countNew + "");
        });

        // 把查询的结果封装进UserReportVO中
        // 返回
        return UserReportVO.builder()
                .dateList(dateList.toString())
                .totalUserList(countAlls.toString())
                .newUserList(countNews.toString())
                .build();


    }
}
